Examples for "An Introduction to Mathematica" faculty workshop

by Marcus McGuff

Asymptotes :

Use Exclusions option to identify asymptotes and ExclusionsStyle->Dashed to make a dashed line there:

Plot[Tan[x],{x,-2π,2π},Exclusions->{Cos[x]==0},ExclusionsStyle->Dashed]

For "trig" units on the x axis:

Plot[Tan[x],{x,-2π,2π},Exclusions->{Cos[x]==0},ExclusionsStyle->Dashed,Ticks->{Range[-2π,2π,π/2],Automatic}]

You can use the asymptote trick for arbitrary rationals, even if you don't bother to factor the denominator.  (This example is also an interesting use of the Manipulate function to make an "interactive" zoom function; it makes an interesting point about looking at graphs at different magnifications.)

Manipulate[Plot[(((x^5)-1)/((x^5)-2(x^4)+3(x^3)-(x^2))),{x,-zoom,zoom},PlotStyle->Red,Exclusions->{(x^3)-2(x^2)+3x-1==0},ExclusionsStyle->Dashed],{zoom,1,20}]

A cool trick to show the horizontal asymptote as well; you could of course just list it, but this allows you to make it work for arbitrary functions:

num[x_]:=4(x^5)-1

denom[x_]:=(x^5)-2(x^4)+3(x^3)-(x^2)

Manipulate[Plot[Evaluate[{((num[x])/(denom[x])),Limit[((num[x])/(denom[x])),x->∞]}],{x,-zoom,zoom},PlotStyle->{Red,Dashed},PlotRange->{-5,60},Exclusions->{denom[x]==0},ExclusionsStyle->Dashed],{zoom,1,20}]

Better yet (I think this is much cooler - find vertical asymptotes by setting 1/f(x)==0):

function[x_]:=((Cos[x]-x Tan[x])/(18Sin[x]-(x^3)))

Manipulate[Plot[function[x],{x,-zoom,zoom},Exclusions->{(1/(function[x]))==0},ExclusionsStyle->Dashed],{zoom,1,20}]

Interestingly enough, these work correctly even when you have a removable discontinuity; it does not get marked as an asymptote.  (However, notice that I did drop the horizontal asymptote; the graph does not behave well if there isn't one but you try to graph it anyway.)  You can, of course, copy-and-paste the graphs you get from these into your tests.

Improper integrals example :

Version 1 :

Let's just plot (1/(x^p)) inside a Manipulate and watch what happens when we vary p.  (I added in a fancy PlotLabel to show the actual integral.  Notice I get an error until I make p>1, since the integral doesn't converge.  I could make this fancier to avoid this, but that doesn't really hurt anything, so let's stay simple.)

Manipulate[Plot[(1/(x^p)),{x,0,10},AxesOrigin->{0,0},PlotRange->{0,1},PlotLabel->Row[{"(∫_1^∞)(1/(x^p))\[DifferentialD]x=",(∫_1^∞)(1/(x^p))\[DifferentialD]x}]],{p,0.1,4}]

This is kind of cool, but I don't really get much of a feel for how it really converges.  We really want the students to get some understanding about how/why it converges for the higher powers.  So, my idea is to plot the area under the curve from 1 to b as a function of b.  If that value keeps getting larger, the area is infinite, but if it levels off, the area is finite; this way students begin to get a feel for how a region of infinite extent can still have finite area.  I tried this using Integrate, but that is way too slow; this shouldn't really be a surprise, since that would recompute the integral for every point on the graph (and again as I vary p). 

So, I used NIntegrate to approximate the integral:

Version 2 :

Manipulate[Plot[NIntegrate[(1/(x^p)),{x,1,b}],{b,1,10000},AxesOrigin->{0,0},AxesLabel->{"b","(∫_1^b)(1/(x^p))\[DifferentialD]x"}],{p,0.1,4}]

Then, I thought, "Why used a fixed upper bound on b?  What if it's just converging slowly?"  So, I added a parameter for the upper bound on b (i.e., the max value on the horizontal axis).  After playing with this a little, I realized what I really wanted was for my new parameter (maxb) to be the magnitude of that number, so I can quickly scale up to very huge numbers for b while still seeing how it behaves for smaller ones:

Version 3 :

Manipulate[Plot[NIntegrate[(1/(x^p)),{x,1,b}],{b,1,(10^maxb)},AxesOrigin->{0,0},AxesLabel->{"b","(∫_1^b)(1/(x^p))\[DifferentialD]x"}],{p,0.1,4},{maxb,1,100,1}]

If you try the above near p=1, you get an error message that the integration is "converging too slowly".  Hmmm...  Maybe NIntegrate wasn't such a great idea after all.

Version 4 :

So, after rethinking things again, I realized that what I should really do is compute the integral for an arbitrary p in advance, so it doesn't have to be recomputed inside the Manipulate.  Since the value of the integral depends on the power p and the upper limit of integration b, I'm going to define a function integral that depends on those two parameters:

integral[p_,b_]=(∫_1^b)(1/(x^p))\[DifferentialD]x

WAIT A SECOND!  I don't know why or how this could be, but Mathematica clearly isn't considering the case where p=1 (it does give conditions on b, but not p).  Sigh...  Fortunately, I can just define the special case where p=1 separately:

integral[1,b_]=Integrate[(1/x),{x,1,b}]

Now we're ready to go with a semi-finished version (pay particular attention to the case where p=1 and nearby; the behavior is definitely not clear there).

Manipulate[Plot[integral[p,b],{b,1,(10^maxb)},AxesOrigin->{0,0},AxesLabel->{"b","(∫_1^b)(1/(x^p))\[DifferentialD]x"}],{p,0.1,4},{maxb,1,100,1}]

Making a more direct interaction : (more advanced)

Sometimes, it's nice to be able to control an example with something more direct than a "slider" control.  You can use a "locator" control to do that.  Let's make a simple example where we can drag two points around and display the slope of the line between them.  

	We create Locator controls for two different points, ptA and ptB (the coordinates given right after each one is the default coordinates for that point - be careful you have the appropriate number of {}'s).  To find the x coordinate of a point, you reference it's component as ptA[[1]] (and of course, ptA[[2]] is the y coordinate).  Notice, I define the slope before I plot the line (be sure you use the semi-colon, so it doesn't print out).

Manipulate[slope=((ptB[[2]]-ptA[[2]])/(ptB[[1]]-ptA[[1]]));Plot[slope(x-ptA[[1]])+ptA[[2]],{x,-6,6},PlotRange->{-6,6},PlotLabel->Row[{"Slope = ",slope,", y = ",Simplify[slope(x-ptA[[1]])+ptA[[2]]]}],GridLines->Automatic,GridLinesStyle->LightGray,AspectRatio->Automatic],
{{ptA,{0,0}},Locator},{{ptB,{1,1}},Locator}]

While this is pretty cool, the fact that it accepts any possible coordinates, makes it hard to choose actually nice numbers for the slope (1/2, 3, etc.).  We can fix that by limiting the domain of ptA and ptB:

Manipulate[ptA=Rationalize[ptA,1/12];ptB=Rationalize[ptB,1/12];slope=((ptB[[2]]-ptA[[2]])/(ptB[[1]]-ptA[[1]]));Plot[slope(x-ptA[[1]])+ptA[[2]],{x,-6,6},PlotRange->{-6,6},PlotLabel->Row[{"Slope = ",slope,", y = ",Simplify[slope(x-ptA[[1]])+ptA[[2]]]}],GridLines->Automatic,GridLinesStyle->LightGray,AspectRatio->Automatic],
{{ptA,{0,0}},Locator},{{ptB,{1,1}},Locator}]

This isn't entirely successful, since it feels like you have to "fight" the points to move them (they keep jumping to the nearest 1/12 of a unit).  This can be fixed, but it takes more work; this gives you some idea.  A less problematical example would be moving a tangent line along a curve:

f[x_]:=x Sin[x]

Manipulate[Plot[{f[x],f[tanPt[[1]]]+f'[tanPt[[1]]](x-tanPt[[1]])},{x,-10,10},PlotRange->{-10,10},PlotStyle->{Red,Blue}],{{tanPt,{0,0}},Locator}]

A bit nicer version hides the little Locator blob, but uses the Epilog function to plot the points on the graph:

Manipulate[Plot[{f[x],f[tanPt[[1]]]+f'[tanPt[[1]]](x-tanPt[[1]])},{x,-10,10},PlotRange->{-10,10},PlotStyle->{Red,Blue},Epilog->{PointSize[0.02],Point[{tanPt[[1]],f[tanPt[[1]]]}]}],{{tanPt,{0,0}},Locator,Appearance->None}]

Answers to questions from workshop

Graphing the cube root

Mathematica insists on taking the principal root of numbers, regardless, so if you try to graph the basic cube root function, you get:

Plot[(x^(1/3)),{x,-2,2}]

Since the principal cube root of a negative number is complex, the left-hand side of the graph doesn't get graphed.

((-1)^(1/3))//N

They seem to have removed the old RealOnly library from Mathematica (which was how you could get around this in the past), so now you have to define your own cubeRoot function as follows:

cubeRoot[x_]:=Sign[x](((Abs[x]))^(1/3))

This ensures that the cube root of a negative is negative.  Now, you can graph it in all its glory:

Plot[cubeRoot[x],{x,-2,2}]

Plotting individual points on the graph of a function

In the workshop, I showed how you could use the Drawing Tools palette to add one or more solid points to a graph.  There were several questions about this, but one asked how to place points at a specific set of coordinates and another asked how to put open and closed points on a piecewise graph.  I offer two solutions:  one manual way to do it you can do yourself and a second automated "widget" that will make graphing piecewise functions easy.

Basic method to add open or closed points at specific locations on an existing graph

First, plot your basic graph and give it a name; it can be piecewise or not:

baseGraph=Plot[(Piecewise[{{-1, x<1}, {1, x≥1}}]),{x,-4,4},PlotRange->{-2,2},ExclusionsStyle->None]

Now, you need to use the ListPlot function to make one graph of all the open points and one graph of all the closed points you want to add (be sure to use the PlotMarkers option I give here):

openPts=ListPlot[{{1,1},{1,-1}},PlotMarkers->{"○",Small}]

Do the same for your closed points:

closedPts=ListPlot[{{1,0}},PlotMarkers->{"●",Small}]

Finally, use Show to combine the graphs:

Show[baseGraph,openPts,closedPts]

You can combine this into one single long Show command and play around with the graph options, but this is one basic technique to do this.  It is a bit of a pain, making 3 graphs, but it does work pretty well.  Fortunately for the lazier ones among you, I decided to automate this whole process into a widget:

Automatic piecewise function plotting widget

In the widget below, you can simply change the given piecewise function to whatever one you want.  You can delete or add additional lines as needed; Mathematica will then auto-detect where to put the open and closed points on your graph.  You can adjust your domain by panning the viewpoint and zooming in/out and choose a color for the graph and whether to show a grid.  If you want some different graphing options, you can either go in and modify the code yourself (double-click on the cell border just outside the box) or ask me about it.  (Warning:  The code has some tricks in it that make it kind of hard to read if you don't know a reasonable amount about Mathematica.)  Once you have the graph you want displayed, you can click on the graph itself and copy-and-paste it into whatever program you want (like Word, for example).  Enjoy.

Manipulate[Module[{plotOpts,plotOptsType,zoomScale,viewDomain,partitionPts,checkLimit,pieces,functionValues,rightLimits,leftLimits,openPts,stuff},

(* Compute domain/range based on location of center and zoom settings *)
zoomScale[factor_]=(factor^3);
viewDomain[centerpt_,var_:0,radius_:zoomScale[zoomFactor]]:=If[NumberQ[var],{-Abs[radius]+centerpt,Abs[radius]+centerpt},
{var,
-Abs[radius]+centerpt,Abs[radius]+centerpt}];

(* Plot options common to all plots *)
plotOpts ={AxesOrigin->{0,0},PlotStyle->graphColor};
If[showGrid,AppendTo[plotOpts,{GridLines->Automatic,GridLinesStyle->Directive[Dotted,Gray]}]];
plotOptsType=Options[Plot];

(*Assign the InputBox function to pieces[]*)
pieces[xTemp_]=pw/.x->xTemp;

(*Scan through the partitions to find the partition points *)
partitionPts=Select[Union[pieces[x][[1,All,2,1]],pieces[x][[1,All,2,2]]],NumberQ];

checkLimit[pt_,direct_]:=Limit[pieces[x],x->pt,Direction->direct];
SetAttributes[pieces,Listable];
SetAttributes[checkLimit,Listable];

functionValues=Select[Transpose[{partitionPts,pieces[partitionPts]}],!MemberQ[#,Indeterminate]&];

openPts=Select[Union[
rightLimits=Transpose[{partitionPts,checkLimit[partitionPts,-1]}],leftLimits=Transpose[{partitionPts,checkLimit[partitionPts,1]}]],!MemberQ[functionValues,#]&];

Show[Plot[pieces[x],Evaluate[viewDomain[viewPt[[1]],x]],PlotRange->Evaluate[viewDomain[viewPt[[2]]]],Evaluate[FilterRules[plotOpts,plotOptsType]]],ListPlot[openPts,PlotMarkers->{"○",Small},Evaluate[FilterRules[plotOpts,plotOptsType]]],ListPlot[functionValues,PlotMarkers->{"●",Small},Evaluate[FilterRules[plotOpts,plotOptsType]]]]

],
{{pw,(Piecewise[{{x+5, x≤-1}, {(x^2), -1<x<2}, {8-x, 2≤x<4}, {2, x==4}, {3Sin[x], x>4}, {Indeterminate, True}}]),"f[x]="}},{{graphColor,Red,"Color"},Red},Style["Zoom"],
{{zoomFactor,1.8,""},6,0.1,ControlType->VerticalSlider},
{{showGrid,False,"Display grid?"},{True,False}},
{{viewPt,{0,0},"Pan viewpoint"},{-20,-20},{20,20}},
ControlPlacement->{Top,Top,Left,Left,Bottom,Bottom}
]

P.S.:  The last line in the piecewise definition (Indeterminate True) should not be deleted.  It is the "Otherwise" case; if you leave any holes in your domain, the value here (Indeterminate) is assigned to those points.  If you delete the line, the default Otherwise case assigns it to 0, which is probably not what you want.  On the other hand, if you want to define a piecewise function like:

(Piecewise[{{(x^2), 0≤x≤1}, {0, Otherwise}}])

the correct way to do this would be:

(Piecewise[{{(x^2), 0≤x≤1}, {0, True}}])

(This line should be the last line in your definition always.)